package com.core.family.admin.service.Impl;

import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.core.common.manger.storage.IStorageService;
import com.core.family.admin.domain.po.PlatStorage;
import com.core.family.admin.mapper.PlatStorageMapper;
import com.core.family.admin.service.PlatStorageService;
import lombok.Data;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 提供存储服务类，所有存储服务均由该类对外提供
 */
@Service
@Data
public class PlatStorageServiceImpl implements PlatStorageService {



    private final IStorageService storage;

    @Resource
    PlatStorageMapper mapper;


    /***
     * 创建临时文件
     * @param inputStream
     * @param fileSuffixName
     * @return
     */
    @SneakyThrows
    @Override
    public PlatStorage createTempMate(InputStream inputStream, String fileSuffixName) {
        if (inputStream.available()<1){
            throw  new Exception("createTempMate inputStream 输入流错误");
        }

        IStorageService.FileMate fileMate=storage.generateFileMateWith("temp",fileSuffixName);
        FileUtil.writeFromStream(inputStream,fileMate.getFilePath());

        PlatStorage platStorage=convert(fileMate);

        String md5=DigestUtils.md5DigestAsHex( new FileInputStream( fileMate.getFilePath() ) );
        platStorage.setFileMd5(md5);
        return platStorage;
    }

    @SneakyThrows
    @Override
    public PlatStorage createTempMate(byte[] data, String fileSuffixName) {
        InputStream stream= new ByteArrayInputStream(data);
        return createTempMate(stream,fileSuffixName);
    }

    /***
     * 新增或更新文件储存，已存储的更新
     * @param inputStream   文件输入流
     * @param contentLength 文件长度
     * @param keyName       文件名包含后缀
     * @return
     */
    @SneakyThrows
    @Override
    public PlatStorage saveOrUpdate(InputStream inputStream, long contentLength, String keyName) {
        PlatStorage temp = createTempMate(inputStream,keyName);

        PlatStorage dbStorage=getByMd5(temp.getFileMd5());
        InputStream inputStream2 = new FileInputStream(temp.getFilePath());
        if (Objects.isNull(dbStorage)){
            //无需考虑多线程，数据库有唯一索引
            FileUtil.del(temp.getFilePath());
            return create(inputStream2,keyName);
        }

        if (dbStorage.getStorageType().equals(storage.getActive())){
//            已有相同存储类型的文件,直接使用, 否则替换
            return dbStorage;
        }

        IStorageService.FileMate fileMate = storage.store(inputStream2,inputStream2.available(),keyName);
        FileUtil.del(temp.getFilePath());

        PlatStorage platStorage=convert(fileMate);
        platStorage.setFileMd5(temp.getFileMd5())
                .setId(dbStorage.getId())
                .setFileLength(contentLength)
                .setStorageType(storage.getActive());

        mapper.updateById(platStorage);

        return platStorage;
    }

    /***
     * 新增文件存储，已存储的直接返回
     * @param inputStream   文件输入流
     * @param keyName       文件名包含后缀
     * @return
     * @throws IOException
     */
    @Override
    public PlatStorage create(InputStream inputStream, String keyName) throws IOException {
        PlatStorage temp = createTempMate(inputStream,keyName);

        PlatStorage dbStorage=getByMd5(temp.getFileMd5());
        InputStream inputStream2 = new FileInputStream(temp.getFilePath());
        if (Objects.nonNull(dbStorage)){
            FileUtil.del(temp.getFilePath());
            return dbStorage;
        }
        IStorageService.FileMate fileMate = storage.store(inputStream2,inputStream2.available(),keyName);
        FileUtil.del(temp.getFilePath());

        PlatStorage platStorage=convert(fileMate);
        platStorage.setFileMd5(temp.getFileMd5())
                .setStorageType(storage.getActive());

        mapper.insert(platStorage);

        return platStorage;

    }

    @Override
    public boolean removeById(Long id) {
       // storage.delete(); 删除实际物理存储
        return true;
    }

    @Override
    public boolean removeByMd5(String md5) {
        // storage.delete(); 删除实际物理存储
        return true;
    }

    @Override
    public List<PlatStorage> getBy(PlatStorage fileLogicMate) {
        LambdaQueryWrapper<PlatStorage> queryWrapper= Wrappers.lambdaQuery(fileLogicMate);

        return mapper.selectList(queryWrapper);
    }

    @Override
    public PlatStorage getByMd5(String md5) {
        PlatStorage fileLogicMate=new PlatStorage().setFileMd5(md5);
        List<PlatStorage> list=getBy(fileLogicMate);
        if (CollectionUtils.isEmpty(list)){
            return null;
        }
        return list.get(0);
    }

    @Override
    public PlatStorage getById(int id) {
        return mapper.selectById(id);
    }


    private PlatStorage convert(IStorageService.FileMate fileMate){

        PlatStorage dbStorage=new PlatStorage()
                .setFileDir(fileMate.getFileDir())
                .setFileKey(fileMate.getFileKey())
                .setFileType(fileMate.getFileType())
                .setFileLength(fileMate.getFileLength())
                .setFilePath(fileMate.getFilePath())
                .setFileUrl(fileMate.getFileUrl());
                //.setFileMd5(md5);
        return dbStorage;
    }

}
